package main

import (
	"fmt"
	"math"
	"time"
	"os/exec"
	"io/ioutil"
)
var size int = 350 * 10000	//350W

func main() {
	exe("uname -a")
	exe("cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c")
	exe("free -h")
	exe("vmstat")

	serial()
	parallel()
}

func serial() {
	for aa := 0; aa < 3; aa++ {
		t := time.Now()			//进入循环即计时

		//分组数组及初始化
		var arr [100]float64
		for i := 0; i < 100; i++ { arr[i] = -1; }

		for i := 0; i < size; i++ {
			var j uint = uint(i % 100)	//分组序号即取模值

			if arr[j] < 0 {	//如果未计算过,就运行一次数学公式
				arr[j] = math.Sqrt(float64(j + 1)) + float64(j >> (j % 5))
			} else {
				arr[j]++	//如果计算过,就递增1
			}
		}

		//将所有分组扩大10000倍后按序号加权求和
		result := 0
		for i := 0; i < 100; i++ { result += (i + 1) * int(math.Floor(arr[i] * 10000)); }

		s := time.Since(t)		//加权求和完成即截止计时
		fmt.Println("SERIAL:		", result, s)
	}
}

func parallel() {
//	for aa := 0; aa < 3; aa ++ {
		t := time.Now()

		var arr [100]float64
		for i := 0; i < 100; i++ { arr[i] = -1; }

		waitAll := make(chan bool, size)		//用于判断所有go routine结束的标志

		var lockArr [100]chan bool				//避免同时访问同一个分组(arr元素)的标志
		for i := 0; i < 100; i++ { lockArr[i] = make(chan bool, 1); }

		for i := 0; i < size; i++ {
			go func(j uint) {
				j %= 100
				val := math.Sqrt(float64(j + 1)) + float64(j >> (j % 5))

				lockArr[j] <- false		//相当于lock(arr[j])

				if arr[j] < 0 {
					arr[j] = val
				} else {
					arr[j]++
				}

				<- lockArr[j]		//相当于unlock(arr[j])

				waitAll <- false	//标志一个go routine完成
			}(uint(i))
		}

		for i := 0; i < size; i++ { <- waitAll; }		//待所有go routine执行完才继续

		//将所有分组扩大10000倍后按序号加权求和
		result := 0
		for i := 0; i < 100; i++ { result += (i + 1) * int(math.Floor(arr[i] * 10000)); }

		s := time.Since(t)		//加权求和完成即截止计时
		fmt.Println("PARALLEL:	", result, s)
//	}
}

func exe(str string) {
	cmd := exec.Command("/bin/bash", "-c", str)
	stdout, _ := cmd.StdoutPipe()
   
	cmd.Start()
	bytes, _ := ioutil.ReadAll(stdout)
  
	cmd.Wait()
	fmt.Printf("%s\n", bytes)
}
